<script lang="ts" setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { Upload, Close } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox, ElImageViewer, type UploadFile } from 'element-plus'
import { uploadBatchFileApi, getAttachmentById } from '@/api/files'
import type { FileUploadParams } from '@/api/files/types'
import { FileUploadStatus, type FileUploadPreviewProps, type FileUploadPreviewEmits, type ExtendedFileInfo } from './types'
import uploadingPlacehodler from '@/assets/athlete/icons/uploading.svg'
import uploadErrorPlacehodler from '@/assets/athlete/icons/uploadError.svg'
import deleteIcon from '@/assets/athlete/icons/delete.svg'
import previewIcon from '@/assets/athlete/icons/eye.svg'

// Props定义
const props = withDefaults(defineProps<FileUploadPreviewProps>(), {
	accept: '.jpg,.jpeg,.png',
	maxSize: 10,
	disabled: false,
	maxCount: 1,
	multiple: false,
	uploadParams: () => ({
		sysCode: 'comp',
		businessCode: 'athlete_register'
	})
})

// 文件上传参数（从prop获取）
const fileUploadParams = computed<FileUploadParams>(() => ({
	sysCode: props.uploadParams?.sysCode || 'comp',
	businessCode: props.uploadParams?.businessCode || 'athlete_register'
}))

// 事件定义
const emit = defineEmits<FileUploadPreviewEmits>()

// 响应式数据
const fileList = ref<ExtendedFileInfo[]>([])
const fileIdList = ref<number[]>([])
const showViewer = ref(false)
const previewUrls = ref<string[]>([])

// 内部更新标志：用于标记 fileIds 变化是否由组件内部触发（上传/删除）
const isInternalUpdate = ref(false)

// el-upload 组件引用
const uploadRef = ref()

// 计算属性
const sizeStyle = computed(() => ({
	width: typeof props.width === 'number' ? `${props.width}px` : props.width,
	height: typeof props.height === 'number' ? `${props.height}px` : props.height
}))

const isUploadDisabled = computed(() => {
	// 如果组件被禁用，直接返回 true
	if (props.disabled) return true
	// 如果 maxCount=1，允许上传（实现替换）
	if (props.maxCount === 1) return false
	// 其他情况，达到上限就禁用
	return fileList.value.length >= props.maxCount
})

const tooltipContent = computed(() => {
	if (props.disabled) return undefined
	// 如果 maxCount=1，提示替换逻辑
	if (props.maxCount === 1) {
		return '上传新文件将替换现有文件'
	}
	return `当前文件数量已经达到${props.maxCount}个上限，请先删除后再上传`
})

// 文件校验
const beforeUpload = (file: File): boolean => {
	const validTypes = ['image/jpeg', 'image/png', 'image/jpg']
	const isValidType = validTypes.includes(file.type)
	const isValidSize = file.size / 1024 / 1024 < props.maxSize

	if (!isValidType) {
		ElMessage.error('只能上传 JPG/PNG 格式的文件!')
		return false
	}
	if (!isValidSize) {
		ElMessage.error(`文件大小不能超过 ${props.maxSize}MB!`)
		return false
	}
	return true
}

// 防止重复处理的标志
const isProcessing = ref(false)

// 文件变化处理（使用Element Plus原生能力）
const handleChange = async (uploadFile: UploadFile, uploadFiles: UploadFile[]) => {
	// 如果正在处理中，直接返回
	if (isProcessing.value) return

	// 单文件上传：直接取最后一个文件
	const lastFile = uploadFiles[uploadFiles.length - 1]
	if (!lastFile || lastFile.status !== 'ready') return

	const newFiles = [lastFile]

	// 设置处理标志，防止重复处理
	isProcessing.value = true

	// 如果 maxCount=1 且已有文件，先清理现有文件（实现替换逻辑）
	if (props.maxCount === 1 && fileList.value.length > 0) {
		// 清理旧文件的 blob URL
		fileList.value.forEach(file => {
			if (file.url?.startsWith('blob:')) {
				URL.revokeObjectURL(file.url)
			}
		})
		// 清空文件列表
		fileList.value = []
		fileIdList.value = []
	}

	// 数量检查（清理后再检查）
	if (fileList.value.length + newFiles.length > props.maxCount) {
		// 如果超出限制，清理 el-upload 的内部文件列表
		if (uploadRef.value) {
			uploadRef.value.clearFiles()
		}
		isProcessing.value = false
		ElMessage.error(`最多只能上传${props.maxCount}张图片`)
		return
	}

	// 转换为内部数据结构
	const extendedFiles: ExtendedFileInfo[] = newFiles.map(file => ({
		uid: file.uid,
		name: file.name,
		size: file.size,
		type: file.raw?.type,
		raw: file.raw,
		status: FileUploadStatus.Uploading,
		progress: 0,
		url: file.raw ? URL.createObjectURL(file.raw) : undefined
	}))

	// 先添加到文件列表，显示上传中状态
	fileList.value.push(...extendedFiles)

	// 批量上传
	try {
		const rawFiles = newFiles.map(f => f.raw!).filter(Boolean)
		const response = await uploadBatchFileApi(rawFiles, fileUploadParams.value)

		// 通过索引找到对应的文件并更新状态
		const uploadedFiles: { fileId: number; file: File }[] = []
		extendedFiles.forEach((extendedFile, index) => {
			// 在fileList中找到对应的文件并更新状态
			const fileIndex = fileList.value.findIndex(f => f.uid === extendedFile.uid)
			if (fileIndex !== -1) {
				fileList.value[fileIndex].status = FileUploadStatus.Success
				fileList.value[fileIndex].fileId = response.data[index]
				fileList.value[fileIndex].progress = 100
				// 收集上传成功的文件信息
				if (extendedFile.raw) {
					uploadedFiles.push({
						fileId: response.data[index],
						file: extendedFile.raw
					})
				}
			}
		})

		// 更新文件ID列表
		fileIdList.value.push(...response.data)

		// 🔑 标记为内部更新，避免 watch 重复调用接口
		isInternalUpdate.value = true
		emit('fileChange', fileIdList.value)
		// 下一个 tick 重置标志
		nextTick(() => {
			isInternalUpdate.value = false
		})

		// 发出文件上传成功事件
		if (uploadedFiles.length > 0) {
			emit('fileUploaded', uploadedFiles)
		}
	} catch (error) {
		// 更新上传失败状态
		extendedFiles.forEach(extendedFile => {
			// 在fileList中找到对应的文件并更新状态
			const fileIndex = fileList.value.findIndex(f => f.uid === extendedFile.uid)
			if (fileIndex !== -1) {
				fileList.value[fileIndex].status = FileUploadStatus.Failed
				fileList.value[fileIndex].errorMessage = '上传失败'
			}
		})
		ElMessage.error('文件上传失败')
	} finally {
		// 无论成功还是失败，都要清除处理标志
		isProcessing.value = false
	}
}

// 预览图片
const previewImage = (url: string): void => {
	previewUrls.value = [url]
	showViewer.value = true
}

// 删除文件
const removeFile = async (index: number): Promise<void> => {
	emit('deleteConfirm', index)

	try {
		await ElMessageBox.confirm('确定要删除吗？', '', {
			confirmButtonText: '确定',
			cancelButtonText: '取消',
			type: 'warning'
		})

		const file = fileList.value[index]

		// 清理blob URL
		if (file.url?.startsWith('blob:')) {
			URL.revokeObjectURL(file.url)
		}

		// 从数组中删除
		fileList.value.splice(index, 1)
		// 只在有效的fileId时才从 fileIdList 中删除
		if (file.fileId && fileIdList.value[index] !== undefined) {
			fileIdList.value.splice(index, 1)
		}

		// 重新整理 fileIdList，确保与 fileList 一一对应
		fileIdList.value = fileList.value.filter(f => f.status === FileUploadStatus.Success && f.fileId).map(f => f.fileId!)

		// 清理 el-upload 的内部文件列表
		if (uploadRef.value) {
			uploadRef.value.clearFiles()
		}

		// 🔑 标记为内部更新，避免 watch 重复调用接口
		isInternalUpdate.value = true
		emit('fileChange', fileIdList.value)
		// 下一个 tick 重置标志
		nextTick(() => {
			isInternalUpdate.value = false
		})

		ElMessage.success('删除成功')
	} catch {
		// 用户取消删除
	}
}

// 重试上传
const retryUpload = async (index: number): Promise<void> => {
	const file = fileList.value[index]
	if (!file.raw) return

	// 更新状态为上传中
	fileList.value[index] = {
		...file,
		status: FileUploadStatus.Uploading,
		progress: 0,
		errorMessage: undefined
	}

	try {
		const response = await uploadBatchFileApi([file.raw], fileUploadParams.value)

		// 更新为成功状态
		fileList.value[index] = {
			...fileList.value[index],
			status: FileUploadStatus.Success,
			fileId: response.data[0],
			progress: 100
		}

		// 更新文件ID列表
		if (fileIdList.value[index] === undefined) {
			fileIdList.value[index] = response.data[0]
		} else {
			fileIdList.value.splice(index, 1, response.data[0])
		}

		// 🔑 标记为内部更新，避免 watch 重复调用接口
		isInternalUpdate.value = true
		emit('fileChange', fileIdList.value)
		// 下一个 tick 重置标志
		nextTick(() => {
			isInternalUpdate.value = false
		})
	} catch (error) {
		// 更新为失败状态
		fileList.value[index] = {
			...fileList.value[index],
			status: FileUploadStatus.Failed,
			errorMessage: '上传失败'
		}
		ElMessage.error('重试上传失败')
	}
}

// 通过文件ID加载文件信息
const loadFilesByIds = async (ids: number[]) => {
	if (!ids || ids.length === 0) {
		// 如果传入空数组，清空文件列表
		fileList.value = []
		fileIdList.value = []
		return
	}

	try {
		const promises = ids.map(id => getAttachmentById(id))
		const responses = await Promise.all(promises)

		const files: ExtendedFileInfo[] = responses.map((res, index) => ({
			uid: `loaded-${ids[index]}-${Date.now()}`,
			name: res.data.originalName,
			size: res.data.fileSize,
			type: res.data.fileType,
			url: res.data.filePath,
			status: FileUploadStatus.Success,
			progress: 100,
			fileId: res.data.id
		}))

		fileList.value = files
		fileIdList.value = ids
	} catch (error) {
		ElMessage.error('加载文件信息失败')
		console.error('加载文件失败:', error)
	}
}

// 监听 fileIds 变化，响应式加载文件
watch(
	() => props.fileIds,
	newFileIds => {
		// 🔑 如果是内部更新（上传/删除触发），跳过接口调用
		if (isInternalUpdate.value) {
			console.log('[FileUploadPreview] 检测到内部更新，跳过接口调用')
			return
		}

		// 外部更新才调用接口加载文件
		if (newFileIds && newFileIds.length > 0 && newFileIds.every(id => id > 0)) {
			console.log('[FileUploadPreview] 检测到外部更新，调用接口加载文件:', newFileIds)
			loadFilesByIds(newFileIds)
		} else if (!newFileIds || newFileIds.length === 0) {
			// 如果传入空数组或undefined，清空文件列表
			console.log('[FileUploadPreview] 清空文件列表')
			fileList.value = []
			fileIdList.value = []
		}
	},
	{
		immediate: true,
		deep: true
	}
)

// 组件挂载时加载初始文件（保留兼容性）
onMounted(() => {
	if (props.fileIds && props.fileIds.length > 0 && props.fileIds.every(id => id > 0)) {
		loadFilesByIds(props.fileIds)
	}
})

// 暴露方法
defineExpose({
	clearFiles: () => {
		fileList.value.forEach(file => {
			if (file.url?.startsWith('blob:')) {
				URL.revokeObjectURL(file.url)
			}
		})
		fileList.value = []
		fileIdList.value = []
		emit('fileChange', [])
	},
	loadFilesByIds
})
</script>

<template>
	<div class="mb-4">
		<!-- 上传按钮 - 使用UnoCSS原子类 -->
		<div :class="{ 'pointer-events-none': disabled }">
			<el-tooltip
				:disabled="!isUploadDisabled"
				:content="tooltipContent"
				placement="top"
			>
				<div class="w-min">
					<el-upload
						ref="uploadRef"
						action="#"
						:auto-upload="false"
						:multiple="false"
						:disabled="isUploadDisabled"
						:before-upload="beforeUpload"
						:on-change="handleChange"
						:show-file-list="false"
						:accept="accept"
					>
						<el-button
							:disabled="isUploadDisabled"
							type="primary"
							class="flex items-center gap-1"
						>
							<el-icon class="text-4"><Upload /></el-icon>
							点击上传
						</el-button>
					</el-upload>
				</div>
			</el-tooltip>
		</div>

		<!-- 图片列表 -->
		<div
			v-if="fileList.length > 0"
			class="flex flex-wrap gap-1 mt-4"
		>
			<div
				v-for="(file, index) in fileList"
				:key="file.uid"
				class="relative group"
				:style="sizeStyle"
			>
				<!-- 图片容器 -->
				<div class="relative w-full h-full">
					<!-- 正常图片 -->
					<img
						v-if="file.status === FileUploadStatus.Success && file.url"
						:src="file.url"
						:alt="file.name"
						class="w-full h-full object-cover cursor-pointer"
						@click="previewImage(file.url!)"
					/>

					<!-- 上传中 -->
					<div
						v-else-if="file.status === FileUploadStatus.Uploading"
						class="w-full h-full flex items-center justify-center bg-blue-50 relative"
					>
						<img
							:src="uploadingPlacehodler"
							alt="上传中"
							class="w-16 h-16 object-cover"
						/>
						<!-- 进度条覆盖层 -->
						<div class="absolute inset-0 bg-black bg-opacity-60 flex items-center justify-center">
							<el-progress
								type="circle"
								:percentage="file.progress || 0"
								:width="50"
							/>
						</div>
					</div>

					<!-- 上传失败 -->
					<div
						v-else-if="file.status === FileUploadStatus.Failed"
						class="w-full h-full flex items-center justify-center bg-red-50 relative"
					>
						<img
							:src="uploadErrorPlacehodler"
							alt="上传失败"
							class="w-16 h-16 object-cover"
						/>
						<!-- 失败图标覆盖层 -->
						<div class="absolute inset-0 bg-red-500 bg-opacity-20 flex items-center justify-center">
							<el-icon class="text-red-500 text-6"><Close /></el-icon>
						</div>
					</div>
				</div>

				<!-- 操作按钮遮罩 -->
				<div
					class="absolute inset-0 bg-black bg-opacity-60 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex items-center justify-center gap-2"
				>
					<!-- 成功状态：预览+删除 -->
					<template v-if="file.status === FileUploadStatus.Success">
						<img
							:src="previewIcon"
							alt="预览"
							class="w-[28px] h-[30px] object-cover cursor-pointer"
							@click="previewImage(file.url!)"
						/>
						<img
							v-if="!disabled"
							:src="deleteIcon"
							alt="删除"
							class="w-[28px] h-[30px] object-cover cursor-pointer"
							@click="removeFile(index)"
						/>
					</template>

					<!-- 失败状态：重试+删除 -->
					<template v-else-if="file.status === FileUploadStatus.Failed">
						<el-button
							size="small"
							@click="retryUpload(index)"
						>
							重试
						</el-button>
						<el-button
							size="small"
							type="danger"
							@click="removeFile(index)"
						>
							删除
						</el-button>
					</template>

					<!-- 上传中状态：取消 -->
					<template v-else-if="file.status === FileUploadStatus.Uploading">
						<el-button
							size="small"
							type="danger"
							@click="removeFile(index)"
						>
							取消
						</el-button>
					</template>
				</div>
			</div>
		</div>

		<!-- 空状态 -->
		<div
			v-else
			class="size-full mt-6"
		>
			<img
				:src="placeholderSrc"
				alt="空状态"
				class="object-cover"
				:width="width"
				:height="height"
			/>
		</div>

		<!-- 图片预览器 -->
		<ElImageViewer
			v-if="showViewer && previewUrls.length > 0"
			:url-list="previewUrls"
			:initial-index="0"
			:hide-on-click-modal="true"
			@close="showViewer = false"
		/>
	</div>
</template>
